package com.ddxcloud.movie.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ddxcloud.common.constants.ResultStatusConstant;
import com.ddxcloud.common.constants.enums.RefundStatusEnum;
import com.ddxcloud.movie.config.alipay.AlipayConfiguration;
import com.ddxcloud.movie.data.constants.AlipayChannelConstant;
import com.ddxcloud.movie.data.constants.PlatformConstant;
import com.ddxcloud.movie.data.dto.PayDTO;
import com.ddxcloud.movie.data.dto.RefundDTO;
import com.ddxcloud.movie.data.entity.Order;
import com.ddxcloud.movie.data.entity.PaymentOrder;
import com.ddxcloud.movie.data.entity.RefundOrder;
import com.ddxcloud.movie.mapper.PaymentOrderMapper;
import com.ddxcloud.movie.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class AlipayServiceImpl implements AlipayService {

    @Resource
    AlipayClient alipayClient;

    @Resource
    AlipayConfiguration alipayConfiguration;

    @Resource
    PaymentOrderService paymentOrderService;

    @Resource
    PaymentOrderMapper paymentOrderMapper;

    @Resource
    OrderService orderService;

    @Resource
    RefundOrderService refundOrderService;

    @Resource
    ChannelService channelService;

    @Override
    public String pay(PayDTO dto, HttpServletRequest request, HttpServletResponse response) {
        dto.setPayChannel(channelService.getChannel().getAlipayChannel());
        PaymentOrder paymentOrder = paymentOrderService.createPaymentOrder(dto, request);
        if (ObjectUtil.isNotEmpty(paymentOrder)) {
            try {
                if (paymentOrder.getPlatform().equals(PlatformConstant.H5)) {
                    this.setChannel(dto.getPayChannel());
                    // 设置请求参数
                    AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
                    alipayRequest.setReturnUrl(alipayConfiguration.getReturn_url());
                    alipayRequest.setNotifyUrl(paymentOrder.getCallbackUrl());

                    // 付款金额（元），必填
                    String total_amount = new BigDecimal(paymentOrder.getPayAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString();
                    // 订单名称，必填
                    String subject = paymentOrder.getProductName();
                    // 商品描述，可空
                    String body = paymentOrder.getProductName();
                    JSONObject bizContent = new JSONObject();
                    bizContent.put("out_trade_no", paymentOrder.getOrderId());
                    bizContent.put("total_amount", total_amount);
                    bizContent.put("subject", subject);
                    bizContent.put("body", body);
                    bizContent.put("product_code", "QUICK_WAP_WAY");
                    alipayRequest.setBizContent(bizContent.toString());

                    AlipayTradeWapPayResponse alipayTradeWapPayResponse = alipayClient.pageExecute(alipayRequest);
                    log.info("alipayTradeWapPayResponse {}", JSONUtil.toJsonStr(alipayTradeWapPayResponse));
                    if(alipayTradeWapPayResponse.isSuccess()) {
                        return alipayTradeWapPayResponse.getBody();
                    }
                } else if (paymentOrder.getPlatform().equals(PlatformConstant.APP)) {
                    alipayClient = new DefaultAlipayClient(alipayConfiguration.getAlipayConfig());
                    // 设置请求参数
                    AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
                    alipayRequest.setNotifyUrl(paymentOrder.getCallbackUrl());

                    // 付款金额（元），必填
                    String total_amount = new BigDecimal(paymentOrder.getPayAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString();
                    // 订单名称，必填
                    String subject = paymentOrder.getProductName();
                    // 商品描述，可空
                    String body = paymentOrder.getProductName();
                    JSONObject bizContent = new JSONObject();
                    bizContent.put("out_trade_no", paymentOrder.getOrderId());
                    bizContent.put("total_amount", total_amount);
                    bizContent.put("subject", subject);
                    bizContent.put("body", body);
                    bizContent.put("product_code", "QUICK_MSECURITY_PAY");
                    alipayRequest.setBizContent(bizContent.toString());

                    AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(alipayRequest);
                    if(alipayTradeAppPayResponse.isSuccess()) {
                        return alipayTradeAppPayResponse.getBody();
                    }
                }
            } catch (AlipayApiException e) {
                log.error("[支付宝] 创建支付订单失败 {}", e.getErrMsg());
            }
        }
        return "";
    }

    @Override
    public String notify(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        try {
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String o : requestParams.keySet()) {
                String[] values = requestParams.get(o);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                // 乱码解决，这段代码在出现乱码时使用。
                // valueStr = new String(valueStr.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
                params.put(o, valueStr);
            }
            log.info("alipay notify params: {}", params);
            // 商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            // 支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            // 交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            if (trade_status.equals("TRADE_SUCCESS")) {
                PaymentOrder paymentOrder = paymentOrderMapper.getOrderByOrderId(out_trade_no);
                if (ObjectUtil.isNotEmpty(paymentOrder)) {
                    boolean res = paymentOrderService.updatePaymentOrderForPaySuccess(paymentOrder);
                    if (res) {
                        res = orderService.updateOrderForPaySuccess(out_trade_no, paymentOrder, request);
                        if (res) {
                            return ResultStatusConstant.SUCCESS;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("alipay notify errMsg: {}", e.getMessage());
        }
        return ResultStatusConstant.FAIL;
    }

    @Override
    public void refund(RefundDTO dto, HttpServletRequest request) {
        PaymentOrder paymentOrder = paymentOrderMapper.getOrderByOrderId(dto.getOrderId());
        if (ObjectUtil.isNotNull(paymentOrder)) {
            RefundOrder refundOrder = refundOrderService.createRefundOrder(dto, paymentOrder, request);
            if (ObjectUtil.isNotEmpty(refundOrder)) {
                // 传递的退款金额单位为分，需要转为元单位
                String refundAmount = new BigDecimal(dto.getRefundAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP).toString();
                // 请求对象,调用支付宝 不同接口，需使用不同对象
                AlipayTradeRefundRequest alipayTradeCloseRequest = new AlipayTradeRefundRequest();
                // 请求参数集合对象,除了公共参数之外,所有参数都可通过此对象传递
                AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
                // 退款的订单号,传入生成支付订单时的订单号即可
                alipayTradeRefundModel.setOutTradeNo(dto.getOrderId());
                // 退款金额（元）
                alipayTradeRefundModel.setRefundAmount(refundAmount);
                // 退款的原因
                alipayTradeRefundModel.setRefundReason(dto.getReason());
                alipayTradeCloseRequest.setBizModel(alipayTradeRefundModel);
                try {
                    if (paymentOrder.getPlatform().equals(PlatformConstant.APP)) {
                        alipayClient = new DefaultAlipayClient(alipayConfiguration.getAlipayConfig());
                    } else if (paymentOrder.getPlatform().equals(PlatformConstant.H5)) {
                        this.setChannel(paymentOrder.getPayChannel());
                    }
                    AlipayTradeRefundResponse refundResponse = alipayClient.execute(alipayTradeCloseRequest);
                    log.info("支付宝退款-响应参数 {}", JSONUtil.toJsonStr(refundResponse));
                    if (null != refundResponse.getFundChange() && !refundResponse.getFundChange().isEmpty()) {
                        // 根据退款标识判断是否退款成功
                        boolean flag = refundResponse.getFundChange().equals("Y");
                        boolean res = refundOrderService.updateRefundOrderForRefund(refundOrder,
                                flag ? RefundStatusEnum.STATUS_1.getCode() : RefundStatusEnum.STATUS_2.getCode());
                        if (flag && res) {
                            Order order = orderService.getById(dto.getOrderId());
                            LambdaUpdateWrapper<Order> orderUpdate = new LambdaUpdateWrapper<>();
                            orderUpdate.set(Order::getRefundAmount, refundAmount);
                            orderUpdate.set(Order::getOrderStatus, dto.getOrderStatus());
                            orderUpdate.eq(Order::getOrderId, order.getOrderId());
                            orderService.update(order, orderUpdate);
                        }
                    }
                } catch (AlipayApiException e) {
                    log.error("支付宝退款失败 {}", e.getErrMsg());
                }
            }
        }
    }

    /**
     * 设置渠道
     * @param payChannel
     */
    private void setChannel(String payChannel) {
        if (payChannel.equalsIgnoreCase(AlipayChannelConstant.DG)) {
            alipayClient = new DefaultAlipayClient(
                    alipayConfiguration.getGateway_url(),
                    alipayConfiguration.getDg_h5_app_id(),
                    alipayConfiguration.getDg_h5_merchant_private_key(),
                    alipayConfiguration.getFormat(),
                    alipayConfiguration.getCharset(),
                    alipayConfiguration.getDg_h5_alipay_public_key(),
                    alipayConfiguration.getSign_type()
            );
        } else if (payChannel.equalsIgnoreCase(AlipayChannelConstant.ZH)) {
            alipayClient = new DefaultAlipayClient(
                    alipayConfiguration.getGateway_url(),
                    alipayConfiguration.getZh_h5_app_id(),
                    alipayConfiguration.getZh_h5_merchant_private_key(),
                    alipayConfiguration.getFormat(),
                    alipayConfiguration.getCharset(),
                    alipayConfiguration.getZh_h5_alipay_public_key(),
                    alipayConfiguration.getSign_type()
            );
        }
    }
}
